函数

您所在的位置:网站首页 close 和closure 函数

函数

#函数| 来源: 网络整理| 查看: 265

1. 延迟调用(defer)1.1.1. Golang延迟调用:defer特性:defer用途:defer 碰上闭包defer f.Close1.1.2. defer陷阱defer 与 closuredefer 与 returndefer nil 函数在错误的位置使用 defer解决方案不检查错误

1. 延迟调用(defer)1.1.1. Golang延迟调用:defer特性: 1. 关键字 defer 用于注册延迟调用。 2. 这些调用直到 return 前才被执。因此,可以用来做资源清理。 3. 多个defer语句,按先进后出的方式执行。 4. defer语句中的变量,在defer声明时就决定了。 defer用途: 1. 关闭文件句柄 2. 锁资源释放 3. 数据库连接释放

go语言 defer

go 语言的defer功能强大,对于资源管理非常方便,但是如果没用好,也会有陷阱。

defer 是先进后出

这个很自然,后面的语句会依赖前面的资源,因此如果先前面的资源先释放了,后面的语句就没法执行了。

package mainimport "fmt"func main() { var whatever [5]struct{} for i := range whatever { defer fmt.Println(i) }}

输出结果:

4 3 2 1 0 defer 碰上闭包package mainimport "fmt"func main() { var whatever [5]struct{} for i := range whatever { defer func() { fmt.Println(i) }() }}

输出结果:

4 4 4 4 4

其实go说的很清楚,我们一起来看看go spec如何说的

Each time a "defer" statement executes, the function value and parameters to the call are evaluated as usualand saved anew but the actual function is not invoked.

也就是说函数正常执行,由于闭包用到的变量 i 在执行的时候已经变成4,所以输出全都是4.

defer f.Close

这个大家用的都很频繁,但是go语言编程举了一个可能一不小心会犯错的例子.

package mainimport "fmt"type Test struct { name string}func (t *Test) Close() { fmt.Println(t.name, " closed")}func main() { ts := []Test{{"a"}, {"b"}, {"c"}} for _, t := range ts { defer t.Close() }}

输出结果:

c closed c closed c closed

这个输出并不会像我们预计的输出c b a,而是输出c c c

可是按照前面的go spec中的说明,应该输出c b a才对啊.

那我们换一种方式来调用一下.

package mainimport "fmt"type Test struct { name string}func (t *Test) Close() { fmt.Println(t.name, " closed")}func Close(t Test) { t.Close()}func main() { ts := []Test{{"a"}, {"b"}, {"c"}} for _, t := range ts { defer Close(t) }}

输出结果:

c closed b closed a closed

这个时候输出的就是c b a

当然,如果你不想多写一个函数,也很简单,可以像下面这样,同样会输出c b a

看似多此一举的声明

package mainimport "fmt"type Test struct { name string}func (t *Test) Close() { fmt.Println(t.name, " closed")}func main() { ts := []Test{{"a"}, {"b"}, {"c"}} for _, t := range ts { t2 := t defer t2.Close() }}

输出结果:

c closed b closed a closed

通过以上例子,结合

Each time a "defer" statement executes, the function value and parameters to the call are evaluated as usualand saved anew but the actual function is not invoked.

这句话。可以得出下面的结论:

defer后面的语句在执行的时候,函数调用的参数会被保存起来,但是不执行。也就是复制了一份。但是并没有说struct这里的this指针如何处理,通过这个例子可以看出go语言并没有把这个明确写出来的this指针当作参数来看待。

多个 defer 注册,按 FILO 次序执行 ( 先进后出 )。哪怕函数或某个延迟调用发生错误,这些调用依旧会被执行。

package mainfunc test(x int) { defer println("a") defer println("b") defer func() { println(100 / x) // div0 异常未被捕获,逐步往外传递,最终终止进程。 }() defer println("c")}func main() { test(0)}

输出结果:

c b a panic: runtime error: integer divide by zero

*延迟调用参数在注册时求值或复制,可用指针或闭包 "延迟" 读取。

package mainfunc test() { x, y := 10, 20 defer func(i int) { println("defer:", i, y) // y 闭包引用 }(x) // x 被复制 x += 10 y += 100 println("x =", x, "y =", y)}func main() { test()}

输出结果:

x = 20 y = 120 defer: 10 120

*滥用 defer 可能会导致性能问题,尤其是在一个 "大循环" 里。

package mainimport ( "fmt" "sync" "time")var lock sync.Mutexfunc test() { lock.Lock() lock.Unlock()}func testdefer() { lock.Lock() defer lock.Unlock()}func main() { func() { t1 := time.Now() for i := 0; i


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3